﻿<?xml version="1.0" encoding="UTF-8" ?>

<!-- $Id: rewriteguide.xml,v 1.6 2003/11/16 13:22:59 egr Exp $ -->
<!-- Оригинальный DOCTYPE нужно комментировать или убирать иначе файл не будет показан -->
<!-- <!DOCTYPE manualpage SYSTEM "../style/manualpage.dtd"> -->
<?xml-stylesheet type="text/xsl" href="../style/manual.ru.xsl"?>

<manualpage>
  <relativepath href=".." />

  <title>Руководство по URL преобразованиям</title>

  <summary>
    <note>
      <p>Оригинал написан<br />
      <cite>Ralf S. Engelschall &lt;rse@apache.org&gt;</cite><br />
      Декабрь 1997</p>
    </note>

    <note>
      <p>Перевод<br />
      <cite>
      Александр Егоров 
      &lt;<a href="http://www.egoroff.spb.ru/">http://www.egoroff.spb.ru/</a>&gt;
      </cite><br />
      Октябрь 2002</p>
    </note>

      <p>Этот документ является дополнением к <a

      href="/portfolio/mod_rewrite.html">документации</a> по <module>mod_rewrite</module>.
      Здесь описываются возможности использования <module>mod_rewrite</module>, входящего в состав Apache,
      для решения типичных практических проблем с URL, возникающих у веб-мастеров
      на практике. Для каждой из проблем по написанию
      наборов правил для URL преобразований, здесь есть детальные описания решений.</p>

  </summary>

  <section id="ToC1">

    <title>Введение в <code>mod_rewrite</code></title>

    <p>Модуль <module>mod_rewrite</module> имеющийся в составе Apache - это потрясающий модуль, 
      т.е. это действительно
      интеллектуальный модуль предоставляющий мощные средства
      для URL преобразований. С ним вы можете делать почти любые
      URL преобразования о которых вы когда-либо мечтали. Цена, которую вы должны
      заплатить - принять его сложность, 
      поскольку главный недостаток <module>mod_rewrite</module>, - 
      это то, что его нелегко понять и использовать
      новичку. И даже эксперты Apache иногда находят новые аспекты
      где им может помочь <module>mod_rewrite</module>.</p>

    <p>Другими словами: с <module>mod_rewrite</module> вы либо сами себе прострелите ногу
      при первом знакомстве, и никогда не будете его снова использовать, 
      или полюбите его на всю оставшуюся жизнь из-за его мощи. Цель этого документа 
      - дать вам несколько простых, работающих примеров, а также помочь вам избежать
      первого разочарования, путём показа готовых решений.</p>

  </section>

  <section id="ToC2">

    <title>Практические решения</title>

    <p>Здесь есть масса практических решений когда-то придуманных либо мной
      либо другими людьми.
      Чувствуйте себя свободнее изучая из этих примеров чёрную магию URL преобразований.</p>

    <note type="warning">ВНИМАНИЕ: В зависимости от конфигурации вашего
          сервера, в вашем конкретном случае, возможно понадобится слегка изменить эти примеры, например добавить
          флаг <code>[PT]</code> когда дополнительно 
          используется <module>mod_alias</module> и <module>mod_userdir</module>,
           и т.д. или переписать набор правил для их работы в контексте каталога - 
          <code>.htaccess</code>, а не в контексте сервера (httpd.conf).  
          Прежде чем использовать конкретный набор правил, 
          всегда пытайтесь понять, что же реально делает. Так Вы избежите проблем.</note>

  </section>

  <section id="url">

    <title>Работа с URL</title>

    <section>

      <title>Реальные URL</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>На некоторых веб-серверах существует более одного URL для 
        какого-либо ресурса. Обычно существуют 
        реальные URL (которые в действительности
        следует использовать и распространять) и те, которые просто являются
        ссылками, внутренними, и т.д. Независимо от того, какой URL пользователь
        применил в своём запросе, в конце концов, он должен увидеть
        только реальный URL.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Для всех виртуальных
          URL, мы делаем внешний HTTP редирект,
          исправляя их и в адресной строке браузера и 
          во всех последующих запросах. В приведённом ниже наборе правил
          <code>/~user</code> заменяется реальным
          <code>/u/user</code> и исправляется отсутствующий завершающий слэш для
          <code>/u/user</code>.</p>

<example><pre>
RewriteRule   ^/<strong>~</strong>([^/]+)/?(.*)    /<strong>u</strong>/$1/$2  [<strong>R</strong>]
RewriteRule   ^/([uge])/(<strong>[^/]+</strong>)$  /$1/$2<strong>/</strong>   [<strong>R</strong>]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Реальные имена хостов</title>

      <dl>
        <dt>Описание:</dt>

        <dd>...</dd>

        <dt>Решение:</dt>

        <dd>
<example><pre>
RewriteCond %{HTTP_HOST}   !^fully\.qualified\.domain\.name [NC]
RewriteCond %{HTTP_HOST}   !^$
RewriteCond %{SERVER_PORT} !^80$
RewriteRule ^/(.*)         http://fully.qualified.domain.name:%{SERVER_PORT}/$1 [L,R]
RewriteCond %{HTTP_HOST}   !^fully\.qualified\.domain\.name [NC]
RewriteCond %{HTTP_HOST}   !^$
RewriteRule ^/(.*)         http://fully.qualified.domain.name/$1 [L,R]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Перемещенный <code>DocumentRoot</code></title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Обычно <directive module="core">DocumentRoot</directive> вебсервера в 
        точности совпадает с URL "/". 
        Однако часто <directive module="core">DocumentRoot</directive> выше по иерархии
        нежели чем URL "/" и в одном <directive module="core">DocumentRoot</directive> 
        могут располагаться несколько сайтов. 
        Например для наших Intranet сайтов <code>/e/www/</code> (главная страница
        WWW), <code>/e/sww/</code> (главная страница для Intranet)
        и т.д. Сейчас из-за того что <directive module="core">DocumentRoot</directive>
        остается "/" для
        <code>/e/www/</code> мы должны обеспечить работу всех подстановок 
        картинок и других объектов во всех последующих запросах этой области.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Мы просто сделаем преобразование URL <code>/</code> в
          <code>/e/www/</code>. С первого взгляда это кажется тривиальным, - 
          однако в действительности, это тривиально только с <module>mod_rewrite</module>. 
          Типичные старые маханизмы URL <em>псевдонимов</em> (что
          делается <module>mod_alias</module> и ему подобными) использовали только совпадение по
          <em>префиксу</em>. В этом случае, вы не можете делать такое
          преобразование, потому что <directive module="core">DocumentRoot</directive> 
          является префиксом для всех
          URL. А с <module>mod_rewrite</module> это действительно тривиально:</p>

<example><pre>
RewriteEngine on
RewriteRule   <strong>^/$</strong>  /e/www/  [<strong>R</strong>]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Проблема отсутствующего завершающего слэша</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Каждый вебмастер может спеть песню о проблеме
        отсутствующих завершающих слэшей при использовании URL ссылающихся на каталоги. 
        Если они отсутствуют, сервер выдает ошибку, потому что если вы пишете
        <code>/~quux/foo</code> вместо <code>/~quux/foo/</code>
        сервер ищет <em>файл</em>
        <code>foo</code>. И поскольку этот файл является каталогом, происходит
        ошибка. В действительности, в большинстве случаев это исправляется само,
        однако, в некоторых случаях, нужно самим эмулировать этот механизм.
        Например, после того, как вы сделали массу
        сложных редиректов URL на CGI скрипты и т.д.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Решение этой тонкой проблемы - это позволить серверу
          добавлять завершающий слэш автоматически. Чтобы сделать это
          правильно, мы должны использовать внешний редирект, для того чтобы
          браузер правильно запрашивал картинки и пр. В случае если бы мы
          сделали только внутренний редирект, это бы работало только для самой страницы
          каталога (страницы по-умолчанию), однако были бы проблемы при наличии любых 
          картинок на этой странице с относительными URL, потому что браузер
          сделал бы запрос на вставку in-lined объекта. Например, запрос
          для <code>image.gif</code> на странице
          <code>/~quux/foo/index.html</code> без внешнего
          редиректа выглядел бы как
          <code>/~quux/image.gif</code>!</p>

          <p>Поэтому, для того чтобы сделать это трюк, мы пишем:</p>

<example><pre>
RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^foo<strong>$</strong>  foo<strong>/</strong>  [<strong>R</strong>]
</pre></example>

          <p>Сумашедший и ленивый может даже сделать следущее в
          файле <code>.htaccess</code> находящемся в корне веб-пространства своего сайта.
          Однако, следует отметить, что это создает некоторые накладные расходы.</p>

<example><pre>
RewriteEngine  on
RewriteBase    /~quux/
RewriteCond    %{REQUEST_FILENAME}  <strong>-d</strong>
RewriteRule    ^(.+<strong>[^/]</strong>)$           $1<strong>/</strong>  [R]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Веб-кластер через один URL</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Мы хотим создать одинаковый и постоянный URL для всех WWW серверов 
        в Intranet веб-кластере, т.е.
        все URL (конкретных локальных серверов и таким образом зависящие
        от сервера!) становятся, в действительности, <em>независимыми</em> от сервера!
        То что мы хотим, - так это дать пространство имен WWW постоянной
        независимой от сервера схеме: никакой URL не должен включать
        какой-либо реальный сервер. Кластер сам должет
        автоматически перенаправлять нас на реальный сервер.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Первое, информация о конкретных серверах берется из
          (распределенных) внешних массивов содержащих информацию о том,
          где находятся наши пользователи, группы и ресурсы. Имеем такую форму:</p>

<example><pre>
user1  server_of_user1
user2  server_of_user2
:      :
</pre></example>

          <p>Мы помещаем эти записи в файлы <code>map.xxx-to-host</code>.
          Второе, мы должны информировать все наши серверы перенаправлять URL
          вида</p>


<example><pre>
/u/user/anypath
/g/group/anypath
/e/entity/anypath
</pre></example>

          <p>на</p>

<example><pre>
http://physical-host/u/user/anypath
http://physical-host/g/group/anypath
http://physical-host/e/entity/anypath
</pre></example>

          <p>если URL не находится на каком-либо локальном сервере. Следующий
          набор правил делает это для нас при помощи файлов c ассоциативными массивами 
          для преобразований (примем что server0 - это сервер, который
          будет использован по-умолчанию, если в массиве нет записи для 
          какого-либо пользователя):</p>

<example><pre>
RewriteEngine on

RewriteMap      user-to-host   txt:/path/to/map.user-to-host
RewriteMap     group-to-host   txt:/path/to/map.group-to-host
RewriteMap    entity-to-host   txt:/path/to/map.entity-to-host

RewriteRule   ^/u/<strong>([^/]+)</strong>/?(.*)   http://<strong>${user-to-host:$1|server0}</strong>/u/$1/$2
RewriteRule   ^/g/<strong>([^/]+)</strong>/?(.*)  http://<strong>${group-to-host:$1|server0}</strong>/g/$1/$2
RewriteRule   ^/e/<strong>([^/]+)</strong>/?(.*) http://<strong>${entity-to-host:$1|server0}</strong>/e/$1/$2

RewriteRule   ^/([uge])/([^/]+)/?$          /$1/$2/.www/
RewriteRule   ^/([uge])/([^/]+)/([^.]+.+)   /$1/$2/.www/$3\
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Перемещение домашних каталогов на другой веб-сервер</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Масса вебмастеров просили решение для следующей
        ситуации: Они хотели просто перенаправить все
        домашние каталоги (пользователей или подсайтов) 
        с одного сервера на другой. Такие вещи, обычно нужны при замене старого сервера новым.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>С mod_rewrite решение тривиально. На нашем старом
          вебсервере мы просто сделаем преобразование всех URL вида
          <code>/~user/anypath</code> в URL вида
          <code>http://newserver/~user/anypath</code>.</p>

<example><pre>
RewriteEngine on
RewriteRule   ^/~(.+)  http://<strong>newserver</strong>/~$1  [R,L]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Структурированные домашние каталоги</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Некоторые сайты с тысячами пользователей обычно используют
        структурированную схему домашних каталогов, т.е. каждый домашний каталог 
        находится в каком-либо подкаталоге, который для примера начинается
        с первой буквы имени пользователя. Поэтому, <code>/~foo/anypath</code>
        имеет путь <code>/home/<strong>f</strong>/foo/.www/anypath</code>
        в то время как <code>/~bar/anypath</code> имеет путь
        <code>/home/<strong>b</strong>/bar/.www/anypath</code>.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Следующий набор правил, используется для раскрытия в URL символа тильды, точно 
          в соответствии с вышеуказанной схемой:</p>

<example><pre>
RewriteEngine on
RewriteRule   ^/~(<strong>([a-z])</strong>[a-z0-9]+)(.*)  /home/<strong>$2</strong>/$1/.www$3
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Реорганизация файловой системы</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Это действительно очень сложный пример: серьёзная вещь,
          очень интенсивно использующая <code>RewriteRules</code>
          в контексте каталогов(.htaccess) для того, чтобы получить 
	  приятный вид данных и и при просмотре их через Интернет чувство того, что
          структура данных никогда не трогается или
          регулируется. Предыстория: <strong><em>net.sw</em></strong> это мой
          архив свободно распространяемого ПО для Unix,
          который я начал собирать в 1992. Для меня это одновременно и хобби
          и работа, потому что изучая компьютерную
          науку, многие годы, в свободное время, я также работал системным и сетевым
          администратором. Каждую неделю мне нужно
          некоторое количество ПО, поэтому я создал глубокую иерархию каталогов,
          где я сохранил эти дистрибутивы:</p>

<example class="language-console"><pre>
drwxrwxr-x   2 netsw  users    512 Aug  3 18:39 Audio/
drwxrwxr-x   2 netsw  users    512 Jul  9 14:37 Benchmark/
drwxrwxr-x  12 netsw  users    512 Jul  9 00:34 Crypto/
drwxrwxr-x   5 netsw  users    512 Jul  9 00:41 Database/
drwxrwxr-x   4 netsw  users    512 Jul 30 19:25 Dicts/
drwxrwxr-x  10 netsw  users    512 Jul  9 01:54 Graphic/
drwxrwxr-x   5 netsw  users    512 Jul  9 01:58 Hackers/
drwxrwxr-x   8 netsw  users    512 Jul  9 03:19 InfoSys/
drwxrwxr-x   3 netsw  users    512 Jul  9 03:21 Math/
drwxrwxr-x   3 netsw  users    512 Jul  9 03:24 Misc/
drwxrwxr-x   9 netsw  users    512 Aug  1 16:33 Network/
drwxrwxr-x   2 netsw  users    512 Jul  9 05:53 Office/
drwxrwxr-x   7 netsw  users    512 Jul  9 09:24 SoftEng/
drwxrwxr-x   7 netsw  users    512 Jul  9 12:17 System/
drwxrwxr-x  12 netsw  users    512 Aug  3 20:15 Typesetting/
drwxrwxr-x  10 netsw  users    512 Jul  9 14:08 X11/
</pre></example>

          <p>В июле 1996 я решил сделать этот архив общедоступным
          всему миру через нормальный веб-интерфейс. "Нормальный" имеется ввиду
          интерфейс где вы можете перемещаться
          прямо по иерархии этого архива. И "нормальный" значит то, что
          я не хотел ничего изменять внутри этой иерархии
          - даже не помещать некоторые CGI скрипты на её 
          верх. Почему? Потому что вышеприведённая структура позже должна была быть
          доступна также и через FTP, и я не хотел наличия там каких-либо
          веб или CGI штук.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Решение состоит из 2-х частей: Первое - это набор CGI
          скриптов которые создают все страницы на лету 
          на всех уровнях каталогов. Я поместил их в
          <code>/e/netsw/.www/</code> в следующем виде:</p>

<example class="language-console"><pre>
-rw-r--r--   1 netsw  users    1318 Aug  1 18:10 .wwwacl
drwxr-xr-x  18 netsw  users     512 Aug  5 15:51 DATA/
-rw-rw-rw-   1 netsw  users  372982 Aug  5 16:35 LOGFILE
-rw-r--r--   1 netsw  users     659 Aug  4 09:27 TODO
-rw-r--r--   1 netsw  users    5697 Aug  1 18:01 netsw-about.html
-rwxr-xr-x   1 netsw  users     579 Aug  2 10:33 netsw-access.pl
-rwxr-xr-x   1 netsw  users    1532 Aug  1 17:35 netsw-changes.cgi
-rwxr-xr-x   1 netsw  users    2866 Aug  5 14:49 netsw-home.cgi
drwxr-xr-x   2 netsw  users     512 Jul  8 23:47 netsw-img/
-rwxr-xr-x   1 netsw  users   24050 Aug  5 15:49 netsw-lsdir.cgi
-rwxr-xr-x   1 netsw  users    1589 Aug  3 18:43 netsw-search.cgi
-rwxr-xr-x   1 netsw  users    1885 Aug  1 17:41 netsw-tree.cgi
-rw-r--r--   1 netsw  users     234 Jul 30 16:35 netsw-unlimit.lst
</pre></example>

          <p>Подкаталог <code>DATA/</code> содержит вышеприведенную структуру 
          каталогов, т.е. настоящие данные
          <strong><em>net.sw</em></strong> и автоматически, время от времени, получает
          обновления через <code>rdist</code>.
          Вторая часть проблемы остается: как связать эти две структуры вместе
          в одно нормальное дерево URL?
          Мы хотим скрыть каталог <code>DATA/</code>
          от пользователя при запуске соответствующих CGI скриптов
          для разных URL. Вот и решение: сначала я поместил
          следующее в конфигурационный файл каталога
          в <directive module="core">DocumentRoot</directive> сервера для преобразования
          объявленного URL <code>/net.sw/</code> во внутренний путь
          <code>/e/netsw</code>:</p>

<example><pre>
RewriteRule  ^net.sw$       net.sw/        [R]
RewriteRule  ^net.sw/(.*)$  e/netsw/$1
</pre></example>

          <p>Первое правило предназначено для запросов у который отсутствует завершающий
          слэш! Второе правило делает нужное преобразование. И затем,
          в конфигурационном файле каталога <code>/e/netsw/.www/.wwwacl</code>, 
          производится полное конфигурирование:</p>

<example><pre>
Options       ExecCGI FollowSymLinks Includes MultiViews

RewriteEngine on

#  устанавливаем префикс /net.sw/
RewriteBase   /net.sw/

#  сначала мы перенаправляем все запросы к корневому каталогу на
#  управляющий cgi скрипт
RewriteRule   ^$                       netsw-home.cgi     [L]
RewriteRule   ^index\.html$            netsw-home.cgi     [L]

#  обрезаем подкаталоги когда
#  браузер запрашивает нас со страниц в подкаталогах
RewriteRule   ^.+/(netsw-[^/]+/.+)$    $1                 [L]

#  и теперь не делаем редирект для локальных файлов
RewriteRule   ^netsw-home\.cgi.*       -                  [L]
RewriteRule   ^netsw-changes\.cgi.*    -                  [L]
RewriteRule   ^netsw-search\.cgi.*     -                  [L]
RewriteRule   ^netsw-tree\.cgi$        -                  [L]
RewriteRule   ^netsw-about\.html$      -                  [L]
RewriteRule   ^netsw-img/.*$           -                  [L]

#  все остальное является подкаталогом и управляется
#  другим cgi скриптом
RewriteRule   !^netsw-lsdir\.cgi.*     -                  [C]
RewriteRule   (.*)                     netsw-lsdir.cgi/$1
</pre></example>

          <p>Некоторые советы по интерпретации:</p>

          <ol>
            <li>Отметьте флаг <code>L</code> (последний) и отсутствие поля подстановки
            ('<code>-</code>') в 4-й части</li>

            <li>Отметьте символ <code>!</code> (не) и флаг <code>C</code> (цепочка)
            в первом правиле последней части</li>

            <li>Отметьте шаблон перехватывающий все запросы в последнем правиле</li>
          </ol>
        </dd>
      </dl>

    </section>

    <section>

      <title>От NCSA imagemap к Apache <code>mod_imap</code></title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>При переходе с веб-сервера NCSA, на более современный
        веб-сервер Apache, масса народу хотят чтобы, этот переход был безболезненный.
        Поэтому они хотят, чтобы страницы, использующие старую программу NCSA
        <code>imagemap</code>, работали и под Apache с новым модулем
        <module>mod_imap</module>. Проблема в том, что есть
        много гиперссылок, ссылающихся на программу
        <code>imagemap</code> через
        <code>/cgi-bin/imagemap/path/to/page.map</code>. В
        Apache необходимо прочитать только
        <code>/path/to/page.map</code>.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Для всех запросов, мы используем глобальное правило удаления на лету 
          ненужного префикса:</p>

<example><pre>
RewriteEngine  on
RewriteRule    ^/cgi-bin/imagemap(.*)  $1  [PT]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Поиск страниц больше чем в одном каталоге</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Иногда необходимо позволить веб-серверу искать страницы
        больше чем в одном каталоге. Здесь вам не помогут ни MultiViews ни 
        другие техники.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Мы пишем явный набор правил который ищет
          файлы в каталогах.</p>

<example><pre>
RewriteEngine on

#   во-первых попытаемся найти это в указанном месте/...
#   ...и если нашли то заканчиваем поиск и сидим и радуемся:
RewriteCond         /your/docroot/<strong>dir1</strong>/%{REQUEST_FILENAME}  -f
RewriteRule  ^(.+)  /your/docroot/<strong>dir1</strong>/$1  [L]

#   во-вторых - попытаемся найти это в pub/...
#   ...и если нашли то заканчиваем поиск и сидим и радуемся:
RewriteCond         /your/docroot/<strong>dir2</strong>/%{REQUEST_FILENAME}  -f
RewriteRule  ^(.+)  /your/docroot/<strong>dir2</strong>/$1  [L]

#   иначе продолжаем для других директив Alias или ScriptAlias,
#   и т.д.
RewriteRule   ^(.+)  -  [PT]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Установка переменных окружения в соответствии с частями URL</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Возможно вы хотите хранить информацию о статусе между
        запросами и использовать URL для её кодирования. Однако не хочется,
        просто для получения этой информации, использовать CGI обработчик всех страниц.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Мы используем правило для того чтобы скрывать информацию о статусе
          и хранить её в переменной окружения которая затем может быть
          использована в XSSI или CGI. Таким образом 
          URL <code>/foo/S=java/bar/</code> преобразуется в
          <code>/foo/bar/</code> и переменная окружения
          <code>STATUS</code> устанавливается в "java".</p>

<example><pre>
RewriteEngine on
RewriteRule   ^(.*)/<strong>S=([^/]+)</strong>/(.*)    $1/$3 [E=<strong>STATUS:$2</strong>]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Виртуальные хосты пользователей</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Предположим - вы хотите предоставлять адреса
        <code>www.<strong>username</strong>.host.domain.com</code>
        для страниц пользователей через записи DNS типа A на той же самой машине
        и без каких либо виртуальных хостов на этой машине.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Для запросов HTTP/1.0 решения нет, однако для запросов
          HTTP/1.1 которые содержат HTTP заголовок Host: мы
          можем использовать следующий набор правил для преобразования
          <code>http://www.username.host.com/anypath</code>
          во внутренний путь <code>/home/username/anypath</code>:</p>

<example><pre>
RewriteEngine on
RewriteCond   %{<strong>HTTP_HOST</strong>}                 ^www\.<strong>[^.]+</strong>\.host\.com$
RewriteRule   ^(.+)                        %{HTTP_HOST}$1          [C]
RewriteRule   ^www\.<strong>([^.]+)</strong>\.host\.com(.*) /home/<strong>$1</strong>$2
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Перенаправление домашних каталогов для чужаков</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Мы хотим перенаправить URL домашних каталогов на другой веб-сервер
        <code>www.somewhere.com</code> когда запрашиваемый пользователь
        не принадлежит локальному домену
        <code>ourdomain.com</code>. Это иногда используется в
        контексте виртуальных хостов.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Просто правило на перенаправление:</p>

<example><pre>
RewriteEngine on
RewriteCond   %{REMOTE_HOST}  <strong>!^.+\.ourdomain\.com$</strong>
RewriteRule   ^(/~.+)         http://www.somewhere.com/$1 [R,L]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Перенаправление несуществующих URL на другой веб-сервер</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Типичный часто задаваемый вопрос по URL преобразованиям - это 
        как перенаправить несуществующие запросы с сервера А на сервер B. Обычно
        это делается через <directive module="core"
          >ErrorDocument</directive> CGI-скрипты на Perl, однако
        с модулем <module>mod_rewrite</module> тоже есть решение. 
        Заметьте однако, что это менее 
        ресурсоёмко чем использвание <directive module="core">ErrorDocument</directive>
        CGI-скрипта!</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Первое решение имеет лучшую производительность однако меньшую
          гибкость и меньшую защиту от ошибок:</p>

<example><pre>
RewriteEngine on
RewriteCond   /your/docroot/%{REQUEST_FILENAME} <strong>!-f</strong>
RewriteRule   ^(.+)                             http://<strong>webserverB</strong>.dom/$1
</pre></example>

          <p>Проблема здесь в том, что это будет работать только для страниц
          находяшихся внутри <directive module="core">DocumentRoot</directive>. 
          Тогда как вы можете добавить больше условий
          (например ещё и для управления домашними каталогами, и т.д.)
          есть лучший вариант:</p>

<example><pre>
RewriteEngine on
RewriteCond   %{REQUEST_URI} <strong>!-U</strong>
RewriteRule   ^(.+)          http://<strong>webserverB</strong>.dom/$1
</pre></example>

          <p>Здесь используется функция опережающей проверки URL (look-ahead),
          присутствующая в <module>mod_rewrite</module>.
          В результате это будет работать для всех типов URL
          и к тому же это безопасно. Однако это снижает производительность 
          веб-сервера, потому что для каждого запроса производится более одного
          внутреннего подзапроса. Поэтому, если ваш веб-сервер имеет
          мощный процессор, используйте этот вариант. Если это медленная машина,
          используйте первый или лучше <directive module="core">ErrorDocument</directive>
          CGI-скрипта.</p>
        </dd>
      </dl>

    </section>

    <section>

      <title>Внешний редирект</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Иногда нам нужно больше контроля над URL (касаемо механизма обрезания
        символов) при преобразованиях. Обычно обрезающие функции URL ядра Apache
        также убирают и якоря, т.е. в
        URL вида "url#anchor". Вы не можете это непосредственно использовать при 
        редиректах с <module>mod_rewrite</module> потому что функция Apache
        uri_escape() также обрезала бы срезаемый символ.
        Как мы можем сделать редирект такому URL?</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Мы должны использовать ляп в программе используя NPH-CGI скрипт
          который делает редирект на себя самого. Потому что здесь не делается
          обрезание (NPH=non-parseable headers). Сначала мы вводим новую
          URL scheme <code>xredirect:</code> в следующей строке
          конфигурационного файла сервера (должно быть одной из последних директив
          ):</p>

<example class="language-perl"><pre>
RewriteRule ^xredirect:(.+) /path/to/nph-xredirect.cgi/$1 \
            [T=application/x-httpd-cgi,L]
</pre></example>

          <p>Это направляет все URL начинающиеся с
          <code>xredirect:</code> через программу
          <code>nph-xredirect.cgi</code>. И эта программа выглядит примерно так
          :</p>

<example class="language-perl"><pre>
#!/path/to/perl
##
##  nph-xredirect.cgi -- NPH/CGI script for extended redirects
##  Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
##

$| = 1;
$url = $ENV{'PATH_INFO'};

print "HTTP/1.0 302 Moved Temporarily\n";
print "Server: $ENV{'SERVER_SOFTWARE'}\n";
print "Location: $url\n";
print "Content-type: text/html\n";
print "\n";
print "&lt;html&gt;\n";
print "&lt;head&gt;\n";
print "&lt;title&gt;302 Moved Temporarily (EXTENDED)&lt;/title&gt;\n";
print "&lt;/head&gt;\n";
print "&lt;body&gt;\n";
print "&lt;h1&gt;Moved Temporarily (EXTENDED)&lt;/h1&gt;\n";
print "The document has moved &lt;a HREF=\"$url\"&gt;here&lt;/a&gt;.&lt;p&gt;\n";
print "&lt;/body&gt;\n";
print "&lt;/html&gt;\n";

##EOF##
</pre></example>

          <p>Это предоставляет вам функции для того чтобы делать перенаправления
          на все URL schemes, т.е. включая те, которые,
          не прямо принимаются <module>mod_rewrite</module>. Для примера
          вы можете сейчас также перенаправить
          <code>news:newsgroup</code> через</p>

<example><pre>
RewriteRule ^anyurl  xredirect:news:newsgroup
</pre></example>

          <note>Замечание: Вы не должны использовать <code>[R]</code> или 
          <code>[R,L]</code> в вышеприведенной
          директиве потому что <code>xredirect:</code> позже, должен быть
          продолжен нашим специальным правилом "pipe through"
          которое приведено выше.</note>
        </dd>
      </dl>

    </section>

    <section>

      <title>Мультиплексор для доступа к архивам</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Вы знаете такую классную вещь как CPAN (Comprehensive Perl Archive
        Network) расположенную по адресу <a
        href="http://www.perl.com/CPAN">http://www.perl.com/CPAN</a>?
        Здесь работает редирект на один из нескольких FTP серверов по всему
        миру, на которых расположено зеркало CPAN и они приблизительно расположены
        рядом с местоположением запращивающего клиента. В действительности
        это может быть названо мультиплексирующей службой доступа к FTP. Хотя
        CPAN работает на CGI скриптах, как можно реализовать похожее решение
        с помощью <module>mod_rewrite</module>?</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Для начала отметим что начиная с версии 3.0.0 <module>mod_rewrite</module> 
          также может использовать "ftp:" префикс при редиректах. И второе, апроксимация 
          местоположения может быть сделана путем ассоциативного массива преобразований 
          <directive module="mod_rewrite">RewriteMap</directive> через домен 
          верхнего уровня, для конкретного клиента. С помощью хитрой цепочки директив мы 
          можем использовать этот домен верхнего уровня в качестве ключа для поиска в 
          нашем ассоциативном массиве мультеплексирования.</p>

<example><pre>
RewriteEngine on
RewriteMap    multiplex                txt:/path/to/map.cxan
RewriteRule   ^/CxAN/(.*)              %{REMOTE_HOST}::$1                 [C]
RewriteRule   ^.+\.<strong>([a-zA-Z]+)</strong>::(.*)$  ${multiplex:<strong>$1</strong>|ftp.default.dom}$2  [R,L]
</pre></example>

<example class="language-perl"><pre>
##
##  map.cxan -- массив мультиплексирования для CxAN
##

de        ftp://ftp.cxan.de/CxAN/
uk        ftp://ftp.cxan.uk/CxAN/
com       ftp://ftp.cxan.com/CxAN/
 :
##EOF##
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Редиректы в зависимости от времени</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Когда нужно применять уловки типа содержания зависящего от времени
        масса вебмастеров все ещё используют CGI скрипты которые
        производят редиректы на специальные страницы. Как это может быть сделано
        через <module>mod_rewrite</module>?</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Есть много переменных названных <code>TIME_xxx</code>
          для условий редиректа. В связке со специальными
          лексикографическими образцами для 
          сравнения <code>&lt;STRING</code>, <code>&gt;STRING</code>
          и <code>=STRING</code> мы можем производить редиректы зависящие от времени:</p>

<example><pre>
RewriteEngine on
RewriteCond   %{TIME_HOUR}%{TIME_MIN} &gt;0700
RewriteCond   %{TIME_HOUR}%{TIME_MIN} &lt;1900
RewriteRule   ^foo\.html$             foo.day.html
RewriteRule   ^foo\.html$             foo.night.html
</pre></example>

          <p>Это выдает содержимое <code>foo.day.html</code>
          при запросе URL <code>foo.html</code> с 07:00 до 19:00 а
          в оставшееся время содержимое
          <code>foo.night.html</code>. Просто класная вещь для какой-либо
          странички...</p>
        </dd>
      </dl>

    </section>

    <section>

      <title>Обратная совместимость при миграции с YYYY на XXXX</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Как возможно сделать URL обратно совместимыми (все ещё 
        существующими виртуально) после миграции документа <code>document.YYYY</code> 
        в документ <code>document.XXXX</code>, т.е. после преобразования 
        кучи <code>.html</code> файлов в файлы <code>.phtml</code>?</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Мы просто оставляем без изменения имя файла и проверяем существование
          нового расширения. Если оно существует, мы оствляем
          это без изменений, иначе мы перенаправляем URL в его 
          реальное местоположение.</p>


<example><pre>
#   набор правил для обратной совместимости при
#   редиректе для document.html в document.phtml
#   тогда и только тогда когда document.phtml существует
#   одноко не является document.html
RewriteEngine on
RewriteBase   /~quux/
#   вычленяем базовое имя, и запоминаем его
RewriteRule   ^(.*)\.html$              $1      [C,E=WasHTML:yes]
#   делаем редирект на document.phtml если он существует
RewriteCond   %{REQUEST_FILENAME}.phtml -f
RewriteRule   ^(.*)$ $1.phtml                   [S=1]
#   иначе делаем откат на предыдущий документ
RewriteCond   %{ENV:WasHTML}            ^yes$
RewriteRule   ^(.*)$ $1.html
</pre></example>
        </dd>
      </dl>

    </section>

  </section>

  <section id="content">

    <title>Управление содержанием</title>

    <section>

      <title>От старого с новому (внутреннее)</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Предположим что мы недавно переименовали страницу
        <code>bar.html</code> в <code>foo.html</code> и сейчас хотим
        для обратной совместимости сделать доступным и старый URL. В действительности
        мы хотим чтобы пользователи использующие старый URL даже не узнали что
        страницы были переименованы.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Мы перенаправим старый URL на новый через внутренний редирект путем
          следующих директив:</p>

<example><pre>
RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^<strong>foo</strong>\.html$  <strong>bar</strong>.html
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>От старого с новому (внешнее)</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Снова предположим что мы недавно переименовали страницу
        <code>bar.html</code> в <code>foo.html</code> и хотим сейчас
        для обратной совместимости сделать доступным и старый URL. Однако, в этот раз
        мы хотимчтобы пользователи использующие старый URL узнали этот
        новый URL, т.е. адресная строка их браузеров также должна измениться.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Мы используем HTTP редирект на новый URL который приведет к
          к изменениям в браузерах(в адресной строке) и таким образом 
          это видят пользователи:</p>

<example><pre>
RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^<strong>foo</strong>\.html$  <strong>bar</strong>.html  [<strong>R</strong>]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Содержимое зависимое от браузера</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Иногда, по крайней мере для важных страниц верхнего уровня 
        необходимо предоставить оптимизированное для конкретного браузера
        содержание, т.е. для одного нужно выдавать полную версию для 
        последних версий Netscape, минимальную для браузеров Lynx
        и промежуточную для всех других.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Мы не можем использовать content negotiation потому что браузеры не
          не представляют свой тип в этой форме. Вместо этого мы должны
          использовать HTTP заголовок "User-Agent". Следующее условие
          делает следующее: Если HTTP заголовок "User-Agent"
          начинается с "Mozilla/3", страница <code>foo.html</code>
          преобразуется в <code>foo.NS.html</code> и редирект
          прекращается. Если браузер "Lynx" или "Mozilla" версий
          1 или 2 URL становится <code>foo.20.html</code>.
          Все остальные браузеры получают страницу <code>foo.32.html</code>.
          Это делается следующим набором директив:</p>

<example><pre>
RewriteCond %{HTTP_USER_AGENT}  ^<strong>Mozilla/3</strong>.*
RewriteRule ^foo\.html$         foo.<strong>NS</strong>.html          [<strong>L</strong>]

RewriteCond %{HTTP_USER_AGENT}  ^<strong>Lynx/</strong>.*         [OR]
RewriteCond %{HTTP_USER_AGENT}  ^<strong>Mozilla/[12]</strong>.*
RewriteRule ^foo\.html$         foo.<strong>20</strong>.html          [<strong>L</strong>]

RewriteRule ^foo\.html$         foo.<strong>32</strong>.html          [<strong>L</strong>]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Динамическое зеркало</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Предположим что есть чудесные страницы на удалённых хостах и мы хотим
        внести их в наше пространство имен(сайт). Для FTP серверов мы бы использовали
        программу <code>зеркало</code> которая в действительности управляет 
        обновлениями копий удалённых данных на локальной машине.
        Для веб-сервера мы могли бы использовать программу
        <code>webcopy</code> которая делает похожие вещи по HTTP. Однако обе
        эти технологии имеют один главный недостток: локальная копия актуальна всегда
        настолько, насколько часто мы запускаем эту программу. Было бы
        намного лучше если бы зеркало было не статическим должно быть
        полное соответствие копий, вне зависимости от частоты запуска этой программы.
        Вместо этого мы хотим динамическое зеркало 
        с автоматическим обновлением данных когда это необходимо
        (обновление данных на удаленном сервере).</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Для обеспечения этой функции мы отобразим удаленную страницу или даже
          полностью удаленный сайт в наше веб-пространство используя
          <dfn>Proxy Throughput</dfn> опцию (флаг <code>[P]</code>):</p>

<example><pre>
RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^<strong>hotsheet/</strong>(.*)$  <strong>http://www.tstimpreso.com/hotsheet/</strong>$1  [<strong>P</strong>]
</pre></example>

<example><pre>
RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^<strong>usa-news\.html</strong>$   <strong>http://www.quux-corp.com/news/index.html</strong>  [<strong>P</strong>]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Обратное динамическое зеркало</title>

      <dl>
        <dt>Описание:</dt>

        <dd>...</dd>

        <dt>Решение:</dt>

        <dd>
<example><pre>
RewriteEngine on
RewriteCond   /mirror/of/remotesite/$1           -U
RewriteRule   ^http://www\.remotesite\.com/(.*)$ /mirror/of/remotesite/$1
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Получение отсутствующих данных из Intranet</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Это хитрый способ виртуального корпоративного
        (внешнего) Internet веб-сервера
        (<code>www.quux-corp.dom</code>), в действительности хранящем
        и управляющем данными расположенными на (внутреннем) Intranet веб-сервере
        (<code>www2.quux-corp.dom</code>) которые защищены 
        firewall'ом. Фокус в том, что на внешнем веб-сервере мы
        получаем запрошенные данные на лету с внутреннего сервера.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Сначала, мы должны убедиться что наш firewall все ещё
          защищает внутренний веб-сервер и что только внешнему
          веб-серверу разрешено получать с него данные.
          Для firewall'a с фильтрацией пакетов мы могли бы для примера
          сконфигурировать набор директив для firewall подобно этому:</p>

<example class="language-console"><pre>
<strong>ALLOW</strong> Host www.quux-corp.dom Port &gt;1024 --&gt; Host www2.quux-corp.dom Port <strong>80</strong><br/>
<strong>DENY</strong>  Host *                 Port *     --&gt; Host www2.quux-corp.dom Port <strong>80</strong>
</pre></example>

          <p>Просто подправьте это чтобы соответствовать вашему синтаксису.
          Теперь мы можем использовать директивы 
          <module>mod_rewrite</module> которые запрашивают
          отсутствующие данные с backend сервера через прокси:</p>

<example><pre>
RewriteRule ^/~([^/]+)/?(.*)          /home/$1/.www/$2
RewriteCond %{REQUEST_FILENAME}       <strong>!-f</strong>
RewriteCond %{REQUEST_FILENAME}       <strong>!-d</strong>
RewriteRule ^/home/([^/]+)/.www/?(.*) http://<strong>www2</strong>.quux-corp.dom/~$1/pub/$2 [<strong>P</strong>]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Балансировка нагрузки</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Предположим что мы хотим сделать балансировку нагрузки для траффика
        <code>www.foo.com</code> на <code>www[0-5].foo.com</code>
        (всего 6 серверов). Как это возможно сделать?</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Есть масса возможных решений этой проблемы.
          Мы обсудим сначала общеизвестный основанный на DNS вариант
          и специфический с помощью <module>mod_rewrite</module>:</p>

          <ol>
            <li>
              <strong>Циклический DNS</strong>

              <p>Самый простой способ для балансировки нагрузки это использование
              функции циклического DNS в DNS сервере BIND. Просто сконфигурируйте
              <code>www[0-9].foo.com</code> как обычно в своем
              DNS сервере с использованием записей типа A(address) т.е.</p>

<example class="language-dns"><pre>
www0   IN  A       1.2.3.1
www1   IN  A       1.2.3.2
www2   IN  A       1.2.3.3
www3   IN  A       1.2.3.4
www4   IN  A       1.2.3.5
www5   IN  A       1.2.3.6
</pre></example>

              <p>Затем, дополнительно добавьте следующую запись:</p>

<example class="language-dns"><pre>
www    IN  CNAME   www0.foo.com.
       IN  CNAME   www1.foo.com.
       IN  CNAME   www2.foo.com.
       IN  CNAME   www3.foo.com.
       IN  CNAME   www4.foo.com.
       IN  CNAME   www5.foo.com.
       IN  CNAME   www6.foo.com.
</pre></example>

              <p>Заметьте что это кажется неправильным, однако в действительности
              это характерная особенность BIND и может быть использована таким способом.
              Однако, теперь, когда происходит разрешение <code>www.foo.com</code>
              , BIND выдает <code>www0-www6</code> - однако
              слегка меняя/перемещая каждый раз порядок.
              Таким образом клиенты распределяются по разным серверам
              . Однако заметьте что это не блестящая схема
              балансировки нагрузки, потому что информация о разрешении имен DNS 
              кэшируется другими серверами имен в сети, поэтому
              при первом разрешении имени <code>www.foo.com</code> клиентом
              на конкретный <code>wwwN.foo.com</code>, все
              последующие запросы также пойдут на это конкретное доменное имя
              <code>wwwN.foo.com</code>. Однако конечный результат хороший
              , потому что общая сумма запросов действительно
              распределяется на разные веб-серверы.</p>
            </li>

            <li>
              <strong>Балансировка нагрузки с помощью DNS</strong>

              <p>Научный метод балансировки нагрузки основанный на DNS
              это использование программы
              <code>lbnamed</code> которая может быть найдена по <a
              href="http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html">
              http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html</a>.
              Эта программа на Perl 5 в связке с вспомогательными средствами,
              представляет настоящую балансировку нагрузки с использованием DNS.</p>
            </li>

            <li>
              <strong>Циклический Proxy</strong>

              <p>В этом варианте мы используем <module>mod_rewrite</module>
              и его proxy функцию. Сначала мы сопоставим
              <code>www0.foo.com</code> реальному
              <code>www.foo.com</code> при помощи простой</p>

<example class="language-dns"><pre>
www    IN  CNAME   www0.foo.com.
</pre></example>

              <p>записи в DNS. Затем мы направляем
              <code>www0.foo.com</code> только на proxy сервер,
              т.е. мы настраиваем эту машину так чтобы все входные URL
              просто пропускались через внутренний proxy на один из
              5-ти других серверов (<code>www1-www5</code>). Для этого
              мы сначала введем набор директив которые взаимодействуют
              со скриптом <code>lb.pl</code> балансировки нагрузки 
              для всех URL.</p>

<example><pre>
RewriteEngine on
RewriteMap    lb      prg:/path/to/lb.pl
RewriteRule   ^/(.+)$ ${lb:$1}           [P,L]
</pre></example>

              <p>Затем мы пишем <code>lb.pl</code>:</p>

<example class="language-perl"><pre>
#!/path/to/perl
##
##  lb.pl -- скрипт балансировки нагрузки
##

$| = 1;

$name   = "www";     # база для имени хоста
$first  = 1;         # первый сервер (здесь не 0, потому что 0 это и есть этот сервер)
$last   = 5;         # последний сервер в цикле
$domain = "foo.dom"; # доменное имя

$cnt = 0;
while (&lt;STDIN&gt;) {
    $cnt = (($cnt+1) % ($last+1-$first));
    $server = sprintf("%s%d.%s", $name, $cnt+$first, $domain);
    print "http://$server/$_";
}

##EOF##
</pre></example>

              <note>Последнее замечание: Почему это полезно? Кажется что
              <code>www0.foo.com</code> все-ещё перегружен? Ответ положительный
              , - он перегружен, однако только простыми proxy
              запросами! Все SSI, CGI, ePerl, и т.д. запросы,
              полностью выполняются другими машинами.
              Это основная идея.</note>
            </li>

            <li>
              <strong>Аппаратный/TCP Round-Robin</strong>

              <p>Для этой задачи есть также доступные аппратные решения. Cisco
              имеет устройство называемое LocalDirector которое производит балансировку
              нагрузки на уровне TCP/IP. В действительности это некоторый 
              вид циклического шлюза стоящего перед
              веб-кластером. Если у вас есть достаточно денег и вас действительно
              нужно высокопроизводительное решение, используйте этот вариант.</p>
            </li>
          </ol>
        </dd>
      </dl>

    </section>

    <section>

      <title>Обратный Proxy</title>

      <dl>
        <dt>Описание:</dt>

        <dd>...</dd>

        <dt>Решение:</dt>

        <dd>
<example><pre>
##
##  apache-rproxy.conf -- Конфигурация Apache для использования обратного Proxy
##

#   тип сервера
ServerType           standalone
Listen               8000
MinSpareServers      16
StartServers         16
MaxSpareServers      16
MaxClients           16
MaxRequestsPerChild  100

#   параметры функционирования сервера
KeepAlive            on
MaxKeepAliveRequests 100
KeepAliveTimeout     15
Timeout              400
IdentityCheck        off
HostnameLookups      off

#   пути для рабочих файлов
PidFile              /path/to/apache-rproxy.pid
LockFile             /path/to/apache-rproxy.lock
ErrorLog             /path/to/apache-rproxy.elog
CustomLog            /path/to/apache-rproxy.dlog "%{%v/%T}t %h -&gt; %{SERVER}e URL: %U"

#   неиспользуемые пути
ServerRoot           /tmp
DocumentRoot         /tmp
CacheRoot            /tmp
RewriteLog           /dev/null
TransferLog          /dev/null
TypesConfig          /dev/null
AccessConfig         /dev/null
ResourceConfig       /dev/null

#   повышаем скорость работы и безопасность
&lt;Directory /&gt;
Options -FollowSymLinks -SymLinksIfOwnerMatch
AllowOverride None
&lt;/Directory&gt;

#   страница состояния для контроля обратного proxy
&lt;Location /apache-rproxy-status&gt;
SetHandler server-status
&lt;/Location&gt;

#   включаем механизм URL преобразований
RewriteEngine        on
RewriteLogLevel      0

#   определяем ассоциативный массив редиректов со списками величин в которых
#   mod_rewrite произвольно выбирает какую-либо из них
RewriteMap     server  rnd:/path/to/apache-rproxy.conf-servers

#   проверка того что страница состояния обрабатывается локально
#   и проверка того, что никто не использует наш proxy кроме нас самих
RewriteRule    ^/apache-rproxy-status.*  -  [L]
RewriteRule    ^(http|ftp)://.*          -  [F]

#   теперь выбираем возможные серверы для конкретных типов URL
RewriteRule    ^/(.*\.(cgi|shtml))$  to://${server:dynamic}/$1  [S=1]
RewriteRule    ^/(.*)$               to://${server:static}/$1

#   и делегируем сгенерированный URL передавая его
#   через proxy-модуль
RewriteRule    ^to://([^/]+)/(.*)    http://$1/$2   [E=SERVER:$1,P,L]

#   и гарантируем что все другие ресурсы запрещены
#   когда они прошли через вышестоящие правила...
RewriteRule    .*                    -              [F]

#   включаем Proxy-модуль без кэширования
ProxyRequests        on
NoCache              *

#   устанавливаем обратное отображение URL для ответов при редиректе
ProxyPassReverse  /  http://www1.foo.dom/
ProxyPassReverse  /  http://www2.foo.dom/
ProxyPassReverse  /  http://www3.foo.dom/
ProxyPassReverse  /  http://www4.foo.dom/
ProxyPassReverse  /  http://www5.foo.dom/
ProxyPassReverse  /  http://www6.foo.dom/
</pre></example>

<example><pre>
##
##  apache-rproxy.conf-servers -- таблица выбора Apache/mod_rewrite
##

#   список backend серверов которые обслуживают статические
#   страницы (HTML файлы и картинки, и т.д.)
static    www1.foo.dom|www2.foo.dom|www3.foo.dom|www4.foo.dom

#   список backend серверов которые обслуживают динамически
#   сгенерированные страницы (CGI программы или mod_perl скрипты)
dynamic   www5.foo.dom|www6.foo.dom
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Новый тип MIME, новая служба</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>В сети есть масса отличных CGI программ. Однако
          их применение обычно надоедает, поэтому многие веб-мастера
          их не используют. Даже функция Action handler Apache'а для
          MIME-типов применима только тогда, когда CGI программы
          не нуждаются в специальных URL (в действительности <code>PATH_INFO</code>
          и <code>QUERY_STRINGS</code>) для них является входом. Сначала,
          давайте настроим новый тип файла с расширением
          <code>.scgi</code> (для защищенных CGI) которые будут обрабатываться
          популярной программой <code>cgiwrap</code>. Проблема здесь заключается в том
          что для этого случая мы используем однородный URL
          (см. выше) и и какой-либо файл находящийся внутри домашних каталогов пользователей
          имеет URL <code>/u/user/foo/bar.scgi</code>. Однако
          <code>cgiwrap</code> требует URL в виде
          <code>/~user/foo/bar.scgi/</code>. Следующая директива решает
          эту проблему:</p>

<example><pre>
RewriteRule ^/[uge]/<strong>([^/]+)</strong>/\.www/(.+)\.scgi(.*) ...
... /internal/cgi/user/cgiwrap/~<strong>$1</strong>/$2.scgi$3  [NS,<strong>T=application/x-http-cgi</strong>]
</pre></example>

          <p>Или предположим что у нас есть несколько полезных программ:
          <code>wwwlog</code> (отображающая
          <code>access.log</code> для поддерева URL и
          <code>wwwidx</code> (запускающая Glimpse на поддереве URL
          ). Мы должны предоставить область URL для этих программ
          чтобы они знали для какой области они должны работать.
          Однако обычно это ужасно, потому что они все время
          запрашиваются из тех областей, т.е. обычно мы бы 
          запускали программу <code>swwidx</code> из
          <code>/u/user/foo/</code> через ссылку</p>

<example class="language-console"><pre>
/internal/cgi/user/swwidx?i=/u/user/foo/
</pre></example>

          <p>которая ужасна. Так как мы должны жестко связывать
          <strong>и</strong> местоположение области
          <strong>и</strong> местонахождение CGI внутри
          гиперссылки. В случае если нам необходимо реорганизовать эту область, 
          мы тратим массу времени меняя различные гиперссылки.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Решение в этом случае это сделать новый специальный формат URL 
          который автоматически приводит к вызову нужного CGI.
          Настраиваем так:</p>

<example><pre>
RewriteRule   ^/([uge])/([^/]+)(/?.*)/\*  /internal/cgi/user/wwwidx?i=/$1/$2$3/
RewriteRule   ^/([uge])/([^/]+)(/?.*):log /internal/cgi/user/wwwlog?f=/$1/$2$3
</pre></example>

          <p>Теперь гиперссылка для поиска
          <code>/u/user/foo/</code> считывает только</p>

<example><pre>
HREF="*"
</pre></example>

          <p>который внутренне автоматически трансформируется в</p>

<example class="language-console"><pre>
/internal/cgi/user/wwwidx?i=/u/user/foo/
</pre></example>

          <p>То же самое приводит к вызову CGI программы для 
          доступа к логам когда используется гиперссылка
          <code>:log</code>.</p>
        </dd>
      </dl>

    </section>

    <section>

      <title>От статики к динамике</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Как можно трансформировать статическую страницу
          <code>foo.html</code> в ее динамический вариант
          <code>foo.cgi</code> незаметным образом, т.е. так чтобы ни браузер
          ни пользователь не заметили этого.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Мы просто перенаправляем URL на CGI-скрипт и корректируем
          MIME-тип так чтобы это действительно работало как CGI-скрипт.
          Таким образом запрос к <code>/~quux/foo.html</code>
          внутренне приведет к вызову
          <code>/~quux/foo.cgi</code>.</p>

<example><pre>
RewriteEngine  on
RewriteBase    /~quux/
RewriteRule    ^foo\.<strong>html</strong>$  foo.<strong>cgi</strong>  [T=<strong>application/x-httpd-cgi</strong>]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Регенерация содержания на лету</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Здесь рассматривается действительно вещь для посвященных: Динамически
          созданные однако статически обслуживаемые страницы, т.е. страницы которые должны
          передаваться как чисто статические (считываемые из файловой системы
          и затем передаваемые по запросу), однако они должны быть динамически сгенерированны
          веб-сервером если они отсутствуют в файловой системе. Таким образом вы можете
          иметь страницы сгенерированные CGI которые 
          являются статически обслуживаемыми если только
          кто-либо (либо планировщик) не удалит статическое содержание. В таком случае
          содержание обновляется.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          Это делается следующим набором директив:

<example><pre>
RewriteCond %{REQUEST_FILENAME}   <strong>!-s</strong>
RewriteRule ^page\.<strong>html</strong>$          page.<strong>cgi</strong>   [T=application/x-httpd-cgi,L]
</pre></example>

          <p>Здесь, запрос к <code>page.html</code> приводит к
          внутреннему запуску соответствующего <code>page.cgi</code> если
          <code>page.html</code> все-ещё отсутствует или имеет нулевой
          размер. Фокус здесь в том что <code>page.cgi</code> это обычный
          CGI скрипт который (в дополнение к собственному <code>STDOUT</code>)
          записывает свой вывод в файл <code>page.html</code>.
          Запустив это один раз, сервер передает данные 
          <code>page.html</code>. Когда вебмастер хочет обновить
          содержание, он просто удаляет
          <code>page.html</code> (обычно с помощью cronjob).</p>
        </dd>
      </dl>

    </section>

    <section>

      <title>Документ с автоматическим обновлением</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Разве это было бы не здорово при создании сложной страницы если бы
          браузер автоматически обновлял эту страницу каждый раз
          когда мы создаем новую её версию в нашем редакторе?
          Невозможно?</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Нет! Мы просто скомбинируем опцию составного MIME веб-сервера,
          опцию NPH вебсервера и мощь <module>mod_rewrite</module> 
          при URL преобразованиях. Сначала, мы реализуем новую
          опцию URL: Простое добавление <code>:refresh</code> к любому
          URL является причиной его обновления каждый раз когда происходит его
          обновление в файловой системе.</p>

<example><pre>
RewriteRule   ^(/[uge]/[^/]+/?.*):refresh  /internal/cgi/apache/nph-refresh?f=$1
</pre></example>

          <p>Теперь когда мы ссылаемся на URL</p>

<example class="language-console"><pre>
/u/foo/bar/page.html:refresh
</pre></example>

          <p>происходит внутренний вызов URL</p>

<example class="language-console"><pre>
/internal/cgi/apache/nph-refresh?f=/u/foo/bar/page.html
</pre></example>

          <p>Единственная отсутствующая часть это NPH-CGI скрипт. Хотя
          обычно говорится что "это остается для упражения читателю"
          ;-) Я также здесь приведу и этот код.</p>

<example class="language-perl"><pre>
#!/sw/bin/perl
##
##  nph-refresh -- NPH/CGI script for auto refreshing pages
##  Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
##
$| = 1;

#   split the QUERY_STRING variable
@pairs = split(/&amp;/, $ENV{'QUERY_STRING'});
foreach $pair (@pairs) {
    ($name, $value) = split(/=/, $pair);
    $name =~ tr/A-Z/a-z/;
    $name = 'QS_' . $name;
    $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
    eval "\$$name = \"$value\"";
}
$QS_s = 1 if ($QS_s eq '');
$QS_n = 3600 if ($QS_n eq '');
if ($QS_f eq '') {
    print "HTTP/1.0 200 OK\n";
    print "Content-type: text/html\n\n";
    print "&amp;lt;b&amp;gt;ERROR&amp;lt;/b&amp;gt;: No file given\n";
    exit(0);
}
if (! -f $QS_f) {
    print "HTTP/1.0 200 OK\n";
    print "Content-type: text/html\n\n";
    print "&amp;lt;b&amp;gt;ERROR&amp;lt;/b&amp;gt;: File $QS_f not found\n";
    exit(0);
}

sub print_http_headers_multipart_begin {
    print "HTTP/1.0 200 OK\n";
    $bound = "ThisRandomString12345";
    print "Content-type: multipart/x-mixed-replace;boundary=$bound\n";
    &amp;print_http_headers_multipart_next;
}

sub print_http_headers_multipart_next {
    print "\n--$bound\n";
}

sub print_http_headers_multipart_end {
    print "\n--$bound--\n";
}

sub displayhtml {
    local($buffer) = @_;
    $len = length($buffer);
    print "Content-type: text/html\n";
    print "Content-length: $len\n\n";
    print $buffer;
}

sub readfile {
    local($file) = @_;
    local(*FP, $size, $buffer, $bytes);
    ($x, $x, $x, $x, $x, $x, $x, $size) = stat($file);
    $size = sprintf("%d", $size);
    open(FP, "&amp;lt;$file");
    $bytes = sysread(FP, $buffer, $size);
    close(FP);
    return $buffer;
}

$buffer = &amp;readfile($QS_f);
&amp;print_http_headers_multipart_begin;
&amp;displayhtml($buffer);

sub mystat {
    local($file) = $_[0];
    local($time);

    ($x, $x, $x, $x, $x, $x, $x, $x, $x, $mtime) = stat($file);
    return $mtime;
}

$mtimeL = &amp;mystat($QS_f);
$mtime = $mtime;
for ($n = 0; $n &amp;lt; $QS_n; $n++) {
    while (1) {
        $mtime = &amp;mystat($QS_f);
        if ($mtime ne $mtimeL) {
            $mtimeL = $mtime;
            sleep(2);
            $buffer = &amp;readfile($QS_f);
            &amp;print_http_headers_multipart_next;
            &amp;displayhtml($buffer);
            sleep(5);
            $mtimeL = &amp;mystat($QS_f);
            last;
        }
        sleep($QS_s);
    }
}

&amp;print_http_headers_multipart_end;

exit(0);

##EOF##
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Массовый виртуальный хостинг</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Опция <directive type="section" module="core"
          >VirtualHost</directive> Apache очень хороша
          и великолепно работает когда у вас есть немного виртуальных хостов.
          Однако когда в являетесь ISP и имеете сотни
          виртуальных хостов это является не лучшим выбором для
          такой задачи.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Для решения этой задачи мы создадим ассоциации страниц на виртуальных хостах 
          или даже полностью всего веб-пространства виртуальных хостов, 
          с ресурсами в нашем пространстве имен(ресурсами основного сервера) 
          с использованием <dfn>Proxy</dfn> функции (флаг <code>[P]</code>):</p>

<example><pre>
##
##  vhost.map
##
www.vhost1.dom:80  /path/to/docroot/vhost1
www.vhost2.dom:80  /path/to/docroot/vhost2
     :
www.vhostN.dom:80  /path/to/docroot/vhostN
</pre></example>

<example><pre>
##
##  httpd.conf
##
    :
#   используем каноническое имя хоста при редиректах, и т.д.
UseCanonicalName on

    :
#   добавляем впереди виртуальный хост формата CLF
CustomLog  /path/to/access_log  "%{VHOST}e %h %l %u %t \"%r\" %&gt;s %b"
    :

#   включаем механизм mod_rewrite на основном сервере
RewriteEngine on

#   определяем два массива: один для коррекции URL и другой для определения
#   доступных виртуальных хостов с соответствующим
#   DocumentRoot.
RewriteMap    lowercase    int:tolower
RewriteMap    vhost        txt:/path/to/vhost.map

#   Теперь делаем реальные ассоциации с виртуальными хостами
#   через большое и сложное одиночное правило:
#
#   1. проверяем что мы не делаем ассоциации с собственными URL
#	(принадлежащими основному серверу)
RewriteCond   %{REQUEST_URL}  !^/commonurl1/.*
RewriteCond   %{REQUEST_URL}  !^/commonurl2/.*
    :
RewriteCond   %{REQUEST_URL}  !^/commonurlN/.*
#
#   2. проверяем что мы имеем заголовок хоста, потому что
#      сейчас наша единственная задача это поддерживать
#      виртуальный хостинг через этот заголовок
RewriteCond   %{HTTP_HOST}  !^$
#
#   3. переводим имя хоста в нижний регистр
RewriteCond   ${lowercase:%{HTTP_HOST}|NONE}  ^(.+)$
#
#   4. ищем имя этого хоста в vhost.map и
#      запоминаем его только тогда, когда оно является путём
#      (а не "NONE" см. выше)
RewriteCond   ${vhost:%1}  ^(/.*)$
#
#   5. наконец мы можем ассоциировать этот URL с местоположением его реального 
#	   document root
#      и запоминаем имя виртуального хоста для записи в журнал
RewriteRule   ^/(.*)$   %1/$1  [E=VHOST:${lowercase:%{HTTP_HOST}}]
    :
</pre></example>
        </dd>
      </dl>

    </section>

  </section>

  <section id="access">

    <title>Ограничение доступа</title>

    <section>

      <title>Блокирование роботов</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Как мы можем заблокировать действительно надоедливых роботов на
          получение страниц из специфических областей сайта? Файла
          <code>/robots.txt</code> содержащего записи 
          "Robot Exclusion Protocol" обычно недостаточно для избавления
          от такого робота.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Мы используем набор правил запрещающие доступ для роботов к URL из
          веб-пространства
          <code>/~quux/foo/arc/</code> (возможно это пространство имеет
          очень глубокую иерархию каталогов, обход которой роботом,
          привел бы к очень большой нагрузке на сервер). Мы должны убедиться что 
          запрещается доступ только для конкретного робота, т.е. просто
          запрет для хоста с которого работает робот недостаточен. 
          Это, также блокировало бы доступ пользователей с этого хоста. Этого эффекта
          мы добьемся проверяя также информацию из HTTP заголовока User-Agent.</p>

<example><pre>
RewriteCond %{HTTP_USER_AGENT}   ^<strong>NameOfBadRobot</strong>.*
RewriteCond %{REMOTE_ADDR}       ^<strong>123\.45\.67\.[8-9]</strong>$
RewriteRule ^<strong>/~quux/foo/arc/</strong>.+   -   [<strong>F</strong>]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Блокирование вставки графических файлов</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Предположим что мы имеем на <code>http://www.quux-corp.de/~quux/</code>
          некоторые страницы на которых у нас есть графические изображения в формате GIF. 
          Эти графические изображения очень хороши, 
          поэтому другие могут помещать их на свои страницы прямо через гиперссылки.
          Нам не нравится эта практика потому что она добавляет бесполезный траффик 
          для нашего сервера.</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>В то время как мы не можем на 100% защитить наши 
          картинки от вставки на другие страницы,
          мы, по крайней мере, можем ограничить случаи в которых браузер
          посылает HTTP заголовок Referer.</p>

<example><pre>
RewriteCond %{HTTP_REFERER} <strong>!^$</strong>
RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
RewriteRule <strong>.*\.gif$</strong>        -                                    [F]
</pre></example>

<example><pre>
RewriteCond %{HTTP_REFERER}         !^$
RewriteCond %{HTTP_REFERER}         !.*/foo-with-gif\.html$
RewriteRule <strong>^inlined-in-foo\.gif$</strong>   -                        [F]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Запрет хоста</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Как мы можем запретить доступ к нашему серверу
          для списка внешних хостов?</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Для Apache версий &gt;= 1.3b6:</p>

<example><pre>
RewriteEngine on
RewriteMap    hosts-deny  txt:/path/to/hosts.deny
RewriteCond   ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND} !=NOT-FOUND [OR]
RewriteCond   ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND} !=NOT-FOUND
RewriteRule   ^/.*  -  [F]
</pre></example>

          <p>Для Apache версий &lt;= 1.3b6:</p>

<example><pre>
RewriteEngine on
RewriteMap    hosts-deny  txt:/path/to/hosts.deny
RewriteRule   ^/(.*)$ ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND}/$1
RewriteRule   !^NOT-FOUND/.* - [F]
RewriteRule   ^NOT-FOUND/(.*)$ ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND}/$1
RewriteRule   !^NOT-FOUND/.* - [F]
RewriteRule   ^NOT-FOUND/(.*)$ /$1
</pre></example>

<example><pre>
##
##  hosts.deny
##
##  ВНИМАНИЕ! Это ассоциативный массив, а не список, даже если мы его относим к списку.
##             mod_rewrite берёт из него пары ключ/значение, поэтому, для каждой записи,
##             должно быть представлено по крайней мере фиктивное значение "-".
##

193.102.180.41 - 
bsdti1.sdm.de  - 
192.76.162.40  - 
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Запрет Proxy</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Как мы можем запретить конкретному хосту или даже пользователю со
          специального хоста использовать proxy нашего Apache?</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Сначала мы должны убедиться что вызов <module>mod_rewrite</module>
          ниже(!) чем вызов <module>mod_proxy</module> в конфигурационном
          файле при сборке Apache. Таким образом он вызывается
          <em>перед</em> <module>mod_proxy</module>. Затем мы
          настраиваем следующий запрет зависящий от хоста...</p>

<example><pre>
RewriteCond %{REMOTE_HOST} <strong>^badhost\.mydomain\.com$</strong>
RewriteRule !^http://[^/.]\.mydomain.com.*  - [F]
</pre></example>

          <p>...и следующий запрет зависящий от пользователя с конкретного хоста:</p>

<example><pre>
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST}  <strong>^badguy@badhost\.mydomain\.com$</strong>
RewriteRule !^http://[^/.]\.mydomain.com.*  - [F]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Вариант специальной аутенфикации</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Иногда необходима очень специфичная аутенфикация, 
          например аутенфикация проверяющая принадлежность к списку
          особых пользователей. Только они могут иметь доступ к какому-либо ресурсу
          и при этом не должно быть окна запроса предлагающего ввести
          данные для аутенфикации (которое появляется
          при использовании базовой аутенфикации через <module>mod_auth_basic</module>).</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Мы используем список условий для для исключения всех кроме
          разрешенных лиц:</p>

<example><pre>
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^friend1@client1.quux-corp\.com$</strong>
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^friend2</strong>@client2.quux-corp\.com$
RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} <strong>!^friend3</strong>@client3.quux-corp\.com$
RewriteRule ^/~quux/only-for-friends/      -                                 [F]
</pre></example>
        </dd>
      </dl>

    </section>

    <section>

      <title>Отражатель основанный на HTTP заголовке Referer</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Как мы можем запрограммировать гибкий отражатель URL который работает
          полагаясь на HTTP заголовок "Referer" и может быть настроен на такое
          количество ссылающихся страниц, какое мы хотим?</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Используйте следующий, действительно хитроумный набор правил...</p>

<example><pre>
RewriteMap  deflector txt:/path/to/deflector.map

RewriteCond %{HTTP_REFERER} !=""
RewriteCond ${deflector:%{HTTP_REFERER}} ^-$
RewriteRule ^.* %{HTTP_REFERER} [R,L]

RewriteCond %{HTTP_REFERER} !=""
RewriteCond ${deflector:%{HTTP_REFERER}|NOT-FOUND} !=NOT-FOUND
RewriteRule ^.* ${deflector:%{HTTP_REFERER}} [R,L]
</pre></example>

          <p>... в связке с соответствующим ассоциативным 
          массивом преобразований:</p>

<example><pre>
##
##  deflector.map
##

http://www.badguys.com/bad/index.html    - 
http://www.badguys.com/bad/index2.html   - 
http://www.badguys.com/bad/index3.html   http://somewhere.com/
</pre></example>

          <p>Это автоматически перенаправит запрос назад на
          ссылающуюся страницу (когда "<code>-</code>" используется в качестве значения
          в массиве) или на конкретный URL (когда в массиве в качестве значения 
          указан какой-либо URL).</p>
        </dd>
      </dl>

    </section>

  </section>

  <section id="other">

    <title>Другое</title>

    <section>

      <title>Внешний механизм преобразований</title>

      <dl>
        <dt>Описание:</dt>

        <dd>
          <p>Часто задаваемый вопрос: Как мы можем решить проблему FOO/BAR/QUUX/и т.д.? 
          Здесь кажется нет решения с использованием
          <module>mod_rewrite</module>...</p>
        </dd>

        <dt>Решение:</dt>

        <dd>
          <p>Использование внешнего массива <directive module="mod_rewrite"
          >RewriteMap</directive>, т.е. программы которая действует
          как <directive module="mod_rewrite"
          >RewriteMap</directive>. Она запускается один раз при старте Apache,
          получает запрошенные URL на <code>входной поток</code> и должна
          помещать результирующиие URL (обычно преобразованные) в
          <code>выходной поток</code> (в том же самом порядке!).</p>

<example><pre>
RewriteEngine on
RewriteMap    quux-map       <strong>prg:</strong>/path/to/map.quux.pl
RewriteRule   ^/~quux/(.*)$  /~quux/<strong>${quux-map:$1}</strong>
</pre></example>

<example class="language-perl"><pre>
#!/path/to/perl

#   отключение буфферизованного I/O который привел бы
#   к бесконечному зацикливанию и зависанию Apache
$| = 1;

#   чтение URL один в строке из входного потока и
#   генерация URL для подстановки в выходной поток
while (&lt;&gt;) {
    s|^foo/|bar/|;
    print $_;
}
</pre></example>

          <p>Это только демонстрационный пример и тут просто все URL 
          <code>/~quux/foo/...</code> преобразуются в
          <code>/~quux/bar/...</code>. В действительности вы можете запрограммировать здесь
          все что угодно. Примите во внимание, что хотя такие массивы и могут быть
          <strong>использованы</strong>, в том числе и обычным пользователем, однако
          <strong>определять</strong> их может только системный администратор.</p>
        </dd>
      </dl>

    </section>

  </section>

</manualpage>
